import * as dgram from 'dgram';
import { Socket } from 'dgram';
import { UdpDataType, UdpMessage, SensorData, GameData, StatusData } from './udp.service';

/**
 * UDP客户端示例 - 展示不同类型数据的传输
 * UDP常用于传输的实时数据类型：
 * 1. 传感器数据 - 物联网设备的温度、湿度等
 * 2. 游戏数据 - 玩家位置、动作等需要低延迟的信息
 * 3. 状态更新 - 设备在线/离线状态
 * 4. 位置数据 - GPS坐标等实时位置信息
 * 5. 简单控制指令 - 远程控制信号
 * 6. 音频/视频流的数据包 - 实时音视频传输
 */
class UdpClientExample {
  private client: Socket;
  private readonly serverHost = 'localhost';
  private readonly serverPort = 3001;
  private readonly clientId: string;
  private intervalIds: NodeJS.Timeout[] = [];
  
  constructor(clientId: string = `client_${Math.random().toString(36).substr(2, 9)}`) {
    this.clientId = clientId;
    this.client = dgram.createSocket('udp4');
    
    this.setupEventListeners();
  }
  
  private setupEventListeners() {
    this.client.on('message', (msg, rinfo) => {
      try {
        // 尝试解析JSON响应
        const response = JSON.parse(msg.toString());
        console.log(`[${new Date().toISOString()}] 收到服务器响应:`, response);
      } catch (e) {
        // 非JSON响应
        console.log(`[${new Date().toISOString()}] 收到服务器消息: ${msg}`);
      }
    });
    
    this.client.on('error', (err) => {
      console.error(`[${new Date().toISOString()}] 客户端错误:`, err);
      this.stop();
    });
    
    this.client.on('close', () => {
      console.log(`[${new Date().toISOString()}] 客户端已关闭`);
    });
  }
  
  // 发送文本消息
  sendTextMessage(message: string) {
    const udpMessage: UdpMessage = {
      type: UdpDataType.TEXT,
      timestamp: Date.now(),
      data: message
    };
    
    this.sendJsonMessage(udpMessage);
  }
  
  // 发送状态更新
  sendStatusUpdate(status: StatusData['status'], batteryLevel?: number) {
    const statusData: StatusData = {
      deviceId: this.clientId,
      status,
      batteryLevel,
      signalStrength: Math.floor(Math.random() * 100)
    };
    
    const udpMessage: UdpMessage = {
      type: UdpDataType.STATUS,
      timestamp: Date.now(),
      data: statusData
    };
    
    this.sendJsonMessage(udpMessage);
  }
  
  // 发送传感器数据（模拟物联网设备）
  sendSensorData() {
    const sensorData: SensorData = {
      deviceId: this.clientId,
      temperature: 20 + Math.random() * 10, // 20-30°C
      humidity: 40 + Math.random() * 30,    // 40-70%
      pressure: 990 + Math.random() * 20    // 990-1010 hPa
    };
    
    const udpMessage: UdpMessage = {
      type: UdpDataType.SENSOR,
      timestamp: Date.now(),
      data: sensorData
    };
    
    this.sendJsonMessage(udpMessage);
    return udpMessage;
  }
  
  // 发送游戏数据（模拟游戏客户端）
  sendGameData(action: string, score?: number) {
    const gameData: GameData = {
      playerId: this.clientId,
      x: Math.random() * 1000,
      y: Math.random() * 1000,
      action,
      score: score ?? Math.floor(Math.random() * 100)
    };
    
    const udpMessage: UdpMessage = {
      type: UdpDataType.GAME,
      timestamp: Date.now(),
      data: gameData
    };
    
    this.sendJsonMessage(udpMessage);
    return gameData;
  }
  
  // 发送位置数据
  sendPositionData(lat: number, lng: number, speed?: number) {
    const positionData = {
      deviceId: this.clientId,
      lat,
      lng,
      speed: speed ?? Math.random() * 120,
      altitude: Math.random() * 1000
    };
    
    const udpMessage: UdpMessage = {
      type: UdpDataType.POSITION,
      timestamp: Date.now(),
      data: positionData
    };
    
    this.sendJsonMessage(udpMessage);
  }
  
  // 通用JSON消息发送方法
  private sendJsonMessage(message: UdpMessage) {
    const messageStr = JSON.stringify(message);
    
    this.client.send(messageStr, this.serverPort, this.serverHost, (err) => {
      if (err) {
        console.error(`[${new Date().toISOString()}] 发送消息失败:`, err);
      } else {
        console.log(`[${new Date().toISOString()}] 已发送${message.type}类型消息`);
      }
    });
  }
  
  // 开始模拟传感器数据发送（定期发送）
  startSimulatingSensorData(intervalMs: number = 2000) {
    const intervalId = setInterval(() => {
      this.sendSensorData();
    }, intervalMs);
    
    this.intervalIds.push(intervalId);
    console.log(`[${new Date().toISOString()}] 开始模拟传感器数据发送，间隔${intervalMs}ms`);
  }
  
  // 开始模拟游戏数据发送（定期发送）
  startSimulatingGameData(intervalMs: number = 500) {
    const actions = ['move', 'jump', 'shoot', 'collect', 'attack'];
    
    const intervalId = setInterval(() => {
      const randomAction = actions[Math.floor(Math.random() * actions.length)];
      this.sendGameData(randomAction);
    }, intervalMs);
    
    this.intervalIds.push(intervalId);
    console.log(`[${new Date().toISOString()}] 开始模拟游戏数据发送，间隔${intervalMs}ms`);
  }
  
  // 停止所有模拟
  stop() {
    // 清除所有定时器
    this.intervalIds.forEach(id => clearInterval(id));
    this.intervalIds = [];
    
    // 发送离线状态
    this.sendStatusUpdate('offline');
    
    // 关闭客户端
    setTimeout(() => {
      this.client.close();
    }, 100);
  }
}

/**
 * 运行不同类型的UDP客户端示例
 * 1. 模拟物联网传感器设备
 * 2. 模拟游戏客户端
 * 3. 模拟位置追踪设备
 */

// 示例1: 模拟物联网传感器设备
function runSensorClientDemo() {
  console.log('=== 启动物联网传感器客户端示例 ===');
  const sensorClient = new UdpClientExample('sensor_1001');
  
  // 发送上线状态
  sensorClient.sendStatusUpdate('online', 95);
  
  // 开始模拟传感器数据发送
  sensorClient.startSimulatingSensorData(3000); // 每3秒发送一次
  
  // 10秒后停止
  setTimeout(() => {
    console.log('=== 传感器客户端演示结束 ===');
    sensorClient.stop();
  }, 10000);
}

// 示例2: 模拟游戏客户端
function runGameClientDemo() {
  console.log('\n=== 启动游戏客户端示例 ===');
  const gameClient = new UdpClientExample('player_8765');
  
  // 发送玩家加入游戏
  gameClient.sendGameData('join', 0);
  
  // 开始模拟游戏数据发送
  gameClient.startSimulatingGameData(1000); // 每1秒发送一次
  
  // 8秒后发送玩家得分
  setTimeout(() => {
    gameClient.sendGameData('score', 1250);
  }, 8000);
  
  // 15秒后停止
  setTimeout(() => {
    console.log('=== 游戏客户端演示结束 ===');
    gameClient.sendGameData('leave');
    gameClient.stop();
  }, 15000);
}

// 示例3: 模拟位置追踪设备
function runPositionClientDemo() {
  console.log('\n=== 启动位置追踪客户端示例 ===');
  const positionClient = new UdpClientExample('vehicle_5432');
  
  // 初始位置 (北京附近)
  let lat = 39.9042;
  let lng = 116.4074;
  
  // 发送初始位置
  positionClient.sendPositionData(lat, lng, 0);
  
  // 模拟移动（定期更新位置）
  const positionInterval = setInterval(() => {
    // 模拟向东北方向移动
    lat += 0.0001;
    lng += 0.0001;
    const speed = 30 + Math.random() * 50; // 30-80 km/h
    
    positionClient.sendPositionData(lat, lng, speed);
  }, 2000);
  
  // 12秒后停止
  setTimeout(() => {
    clearInterval(positionInterval);
    console.log('=== 位置追踪客户端演示结束 ===');
    positionClient.stop();
  }, 12000);
}

// 运行所有演示
function runAllDemos() {
  // 依次启动各个演示
  runSensorClientDemo();
  
  // // 延迟启动游戏客户端
  // setTimeout(() => {
  //   runGameClientDemo();
  // }, 2000);
  
  // // 延迟启动位置客户端
  // setTimeout(() => {
  //   runPositionClientDemo();
  // }, 4000);
}

// 运行演示
console.log('UDP客户端实战演示开始...');
runAllDemos();

// 如何运行此示例:
// 1. 确保UDP服务器已启动 (nestjs应用运行中)
// 2. 在单独的终端运行: bun dist/udp/udp-client.example.js